package account.webapi;

import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ValidationException;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@ControllerAdvice
class AppErrorHandler {

    @ExceptionHandler(value = {HttpMessageNotReadableException.class})
    public @ResponseBody
    Result<?> httpErrorHandler(HttpMessageNotReadableException e, HttpServletRequest request) {
        List<String> reasonList = new ArrayList<>();
        Throwable rootCause = e.getRootCause();
        if (null != rootCause) {
            reasonList.add(rootCause.getMessage());
        }
        Throwable cause = e.getCause();
        if (cause instanceof InvalidFormatException err) {
            String reason = String.format("输入值“%s”无法被解析为%s格式: %s",
                    err.getValue(), err.getTargetType().getName(), err.getClass().getSimpleName());
            reasonList.add(reason);
        }
        return new ResultError(AppErrorCode.BAD_REQUEST)
                .withAdditionalErrorMsgList(reasonList)
                .withAdditionalErrorMsg("Request URL: "+ request.getRequestURL());
    }

    @ExceptionHandler(value = {ValidationException.class})
    public @ResponseBody
    Result<?> validationErrorHandler1(ValidationException e, HttpServletRequest request) {
        String reason = "检测到无效参数: " + e.getMessage();
        return new ResultError(AppErrorCode.BAD_REQUEST)
                .withAdditionalErrorMsg(reason)
                .withAdditionalErrorMsg("Request URL: "+ request.getRequestURL());
    }

    @ExceptionHandler(value = {MethodArgumentNotValidException.class, BindException.class})
    public @ResponseBody
    Result<?> validationErrorHandler2(BindException e, HttpServletRequest request) {
        BindingResult bindingResult = e.getBindingResult();
        List<FieldError> allErrors = bindingResult.getFieldErrors();
        ArrayList<String> list = new ArrayList<>();
        int cnt = 0;
        for (FieldError err : allErrors) {
            list.add(String.format("%d. 字段'%s': %s: %s", ++cnt, err.getField(), err.getDefaultMessage(), err.getRejectedValue()));
        }
        int total = e.getErrorCount();
        list.add(String.format("Total: %d Error%s", total, (total>1)? "s":""));
        return new ResultError(AppErrorCode.BAD_REQUEST)
                .withAdditionalErrorMsgList(list)
                .withAdditionalErrorMsg("Request URL: "+ request.getRequestURL());
    }

    @ExceptionHandler(value = {AppRuntimeException.class})
    public @ResponseBody
    Result<?> appRuntimeExceptionHandler(AppRuntimeException e, HttpServletRequest request) {
        return new ResultError(e.getErrorCode())
                .withAdditionalErrorMsg(e.getMessage())
                .withAdditionalErrorMsg("Request URL: "+ request.getRequestURL());
    }

    @ExceptionHandler(value = {RuntimeException.class})
    public @ResponseBody
    Result<?> otherRuntimeExceptionHandler(RuntimeException e, HttpServletRequest request) {
        e.printStackTrace();
        String reason = "检测到其他运行时错误: " + e.getMessage();
        return new ResultError(AppErrorCode.OTHER_UNEXPECTED_RUNTIME_ERROR)
                .withAdditionalErrorMsg(reason)
                .withAdditionalErrorMsg("Request URL: "+ request.getRequestURL());
    }
}
